/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.cobra.server.servers.implementations;

import org.apache.log4j.Logger;

import com.google.gson.Gson;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.EvidenceInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.LWPException;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.ModelInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.QueryInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.UserInfo;
import com.sri.ai.lpitools.cobra.server.data.api.DataInterface;
import com.sri.ai.lpitools.cobra.server.data.implementations.SQLiteDataImp;
import com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer;


public class COBRAServerWrapper implements COBRAServer {

	private Logger logger = Logger.getLogger(getClass());
	private DataInterface dataInterface;

	public COBRAServerWrapper(){
		//TODO the db file should be configurable
		dataInterface = new SQLiteDataImp("test.db", true);
		createInitialAdminUser();
	}
	
	/**
	 * This method is used to create an initial admin user if one does not exist in the data set
	 * 
	 */
	private void createInitialAdminUser() {
		try {
			if(dataInterface != null ){
				String adminUser = dataInterface.checkUser("admin");
				if(adminUser == null){
					String user = new Gson().toJson(new UserInfo("admin", true));
					dataInterface.saveUser(user);
					initEvidence();
					initQueries();
					initModels();
				}
			}
		} catch (LWPException e) {
			logger.error(e.getMessage(), e);
		}
		
	}
	private void initEvidence() {
		try {
		
			EvidenceInfo evidence1 = new EvidenceInfo();
			evidence1.setEvidence("parfactors({[if rich(bob) then 1 else 0]})");
			evidence1.setUser("admin");
			evidence1.setEvidenceTitle("E1");
			
			dataInterface.saveEvidence("admin", "E1", new Gson().toJson(evidence1));
			
			EvidenceInfo evidence2 = new EvidenceInfo();
			evidence2.setUser("admin");
			evidence2.setEvidence("parfactors({[if rich(bob) then 1 else 0]})");
			evidence2.setEvidenceTitle("E2"); 
			
			dataInterface.saveEvidence("admin", "E2", new Gson().toJson(evidence2));	
		} catch (LWPException e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	private void initQueries() {
		try {
			QueryInfo query1 = new QueryInfo();
			query1.setQuery("belief([rich(bob)])");
			query1.setQueryTitle("Is Bob Rich?");
			query1.setUser("admin");
			dataInterface.saveQuery("admin", "Is Bob Rich?", new Gson().toJson(query1));
			
			QueryInfo query2 = new QueryInfo();
			query2.setQuery("belief([rich(Ann)])");
			query2.setQueryTitle("Is Ann Rich?"); 
			query2.setUser("admin");
			dataInterface.saveQuery("admin", "Is Ann Rich?", new Gson().toJson(query2));
	
			QueryInfo query3 = new QueryInfo();
			query3.setQuery("belief([sick(X)])");
			query3.setQueryTitle("Is Sick?"); 	
			query3.setUser("admin");	
			dataInterface.saveQuery("admin", "Is Sick?", new Gson().toJson(query3));
		} catch (LWPException e) {
			logger.error(e.getMessage(), e);
		}

	}
	private void initModels() {
		try {
			String model = "'Gave Treasure To', \\n'An example of how hard it is to model things without aggregate factors.',\\n sort(People, Unknown, { ann, bob }),\\n sort(Treasure, Unknown, { gold, silver, diamonds }),\\n randomVariable(gaveTreasureTo, 3, People, Treasure, People),\\n randomVariable(owns, 2, People, Treasure, Boolean),\\n randomVariable(rich, 1, People, Boolean),\\n parfactors(union({{(on X in People, Y in People, Z in Treasure)\\n [if gaveTreasureTo(X,Z,Y) then (if owns(Y,Z) then 1 else 0)  else 1]}},\\n {{(on X in People, Z in Treasure) [if owns(X,Z) then if rich(X) then 1 else 0 else 1] }}))";
			String model2Sample = "'Epidemic and Sick with Symptons Example',\\n 'An example of the interplay between symptoms.',\\n sort(People, 10, { bob, dave, rodrigo, ciaran }),\\n randomVariable(epidemic, 0),\\n randomVariable(sick, 1, People, Boolean),\\n "
					+ "randomVariable(fever, 1, People, Boolean),\\n randomVariable(rash, 1, People, Boolean),\\n randomVariable(notAtWork, 1, People, Boolean),\\n "
					+"parfactors(union({[if epidemic then 0.001 else 0.999]},\\n {{(on X in People) [if epidemic then if sick(X)\\n then 0.6 else 0.4 else if sick(X) then 0.05 else 0.95]}},\\n {{(on X in People) [if sick(X) then if fever(X) then 0.7 else 0.3 else if fever(X) then 0.01 else 0.99]}},\\n {{(on X in People) [if sick(X) then if rash(X) then 0.6 else 0.4 else if rash(X) then 0.07 else 0.93]}},\\n {{(on X in People) [if sick(X) then if notAtWork(X) then 0.8 else 0.2 else if notAtWork(X) then 0.05 else 0.95]}},\\n {[if notAtWork(dave) then 0.001 else 0.999]}))";
	
			ModelInfo model1 = new ModelInfo("admin", "admin test Model 1", "Model 1 for admin test", model+"");
			String model1S = new Gson().toJson(model1);
			dataInterface.saveModel("admin", "admin test Model 1", model1S);
			
			ModelInfo model2 = new ModelInfo("admin", "admin test Model 2", "Model 2 for admin test", model2Sample+"");		
			String model2S = new Gson().toJson(model2);

			dataInterface.saveModel("admin", "admin test Model 2", model2S);
		} catch (LWPException e) {
			logger.error(e.getMessage(), e);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#getUsers()
	 */
	@Override
	public String getUsers() throws LWPException {
		return dataInterface.getUsers();
	}
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#authenticateUser(java.lang.String, java.lang.String)
	 */
	@Override
	public String authenticateUser(String user) throws LWPException {
		String userInfo = dataInterface.checkUser(user);
		if(userInfo == null){
			userInfo = "NA";
		}
		return userInfo;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#addUser(java.lang.String)
	 */
	@Override
	public boolean saveUser(String user) throws LWPException {
		return dataInterface.saveUser(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#deleteUser(java.lang.String)
	 */
	@Override
	public boolean deleteUser(String user) throws LWPException {
		return dataInterface.deleteUser(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#listModels(java.lang.String)
	 */
	@Override
	public String listModels(String user) throws LWPException {
		return dataInterface.getModelList(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#getModel(java.lang.String)
	 */
	@Override	
	public String getModelByName(String user, String modelTitle) throws LWPException {
		return dataInterface.openModel(user, modelTitle);
	}	
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#listQueries(java.lang.String)
	 */
	@Override
	public String listQueries(String user) throws LWPException {
		return dataInterface.listQueries(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#listEvidences(java.lang.String)
	 */
	@Override
	public String listEvidences(String user) throws LWPException {
		return dataInterface.listEvidences(user);
	}	

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#getQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public String getQuery(String user, String queryTitle) throws LWPException {
		return dataInterface.getQuery(user, queryTitle);
	}

	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#getEvidences(java.lang.String, java.lang.String)
	 */
	@Override
	public String getEvidence(String user, String evidencesTitle) throws LWPException {
		return dataInterface.getEvidence(user, evidencesTitle);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#saveModel(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override	
	public boolean saveModel(String user, String title, String model) throws LWPException {
		return dataInterface.saveModel(user, title, model);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#saveModelInfo(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveModelInfo(String user, String title, String model) throws LWPException {

		return dataInterface.saveModelInfo(user, title, model);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#saveModelBody(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveModelBody(String user, String title, String model) throws LWPException {
		
		return dataInterface.saveModelBody(user, title, model);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#saveQuery(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override	
	public boolean saveQuery(String user, String title, String query) throws LWPException {
		return dataInterface.saveQuery(user, title, query);

	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#deleteModel(java.lang.String)
	 */
	@Override
	public boolean deleteModel(String user, String modelTitle) throws LWPException {
		return dataInterface.deleteModel(user, modelTitle);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.server.servers.api.COBRAServer#deleteQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteQuery(String user, String queryTitle) throws LWPException {
		return dataInterface.deleteQuery(user, queryTitle);
	}
	
	@Override
	public boolean saveEvidences(String user, String title, String evidences) throws LWPException {
		return dataInterface.saveEvidence(user, title, evidences);

	}

	@Override
	public boolean deleteEvidences(String user, String evidencesTitle) throws LWPException {
		return dataInterface.deleteEvidence(user, evidencesTitle);
	}
	
	@Override
	public void close() throws LWPException {
		dataInterface.close();
		
	}

}
